package io.kblog.support

import com.fasterxml.jackson.databind.ObjectMapper
import kotlin.reflect.KClass


class JacksonJsonSerializer {
    var mapper = ObjectMapper()
    private var jacksonFilter = JacksonJsonFilter()

    /**
     * @param clazzMap target type
     */
    fun filter(clazzMap: Map<KClass<*>?, Map<String, String>>?) {
        if (clazzMap == null) return
        clazzMap.entries.forEach { clazz ->
            clazz.value["include"]?.let { include ->
                if (include.isNotEmpty()) {
                    jacksonFilter.include(
                        clazzMap,
                        clazz.key,
                        include.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                    )
                }
            }
            clazz.value["filter"]?.let { filter ->
                if (filter.isNotEmpty()) {
                    jacksonFilter.filter(
                        clazzMap,
                        clazz.key,
                        filter.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
                    )
                }
            }
            mapper.addMixIn(clazz.key?.java, jacksonFilter.javaClass)
        }
    }

    fun toJson(`object`: Any): String {
        mapper.setFilterProvider(jacksonFilter)
        return mapper.writeValueAsString(`object`)
    }

    fun filter(json: JSON) {
        this.filter(mapOf(json.type to mapOf("include" to json.include, "filter" to json.filter)))
    }

    fun filter(vararg jsonArray: JSON) {
        this.filter(jsonArray.fold(ArrayList<Map.Entry<KClass<*>?, Map<String, String>>>()) { acc, elements ->
            acc.apply {
                addAll(
                    mapOf(
                        elements.type to mapOf(
                            "include" to elements.include,
                            "filter" to elements.filter
                        )
                    ).entries
                )
            }
        }.associateBy({ it.key }, { it.value }))
    }
}